﻿/*
 * Based on code submited by Hamed_ji  (http://www.codeproject.com/cs/library/Do_Anything_With_ID3.asp)
 */

using System;
using System.IO;


/*
 * This namespace contain frames that their base information is text(string)
 */

namespace svs.Mobile.BeyondMedia.FeedCore.ID3v2
{
	/// <summary>
	/// A class for frame that only include Text member
	/// </summary> 
	public abstract class TextOnlyFrame : FrameBase
	{
		private string _Text; // Contain text of current frame

		protected TextOnlyFrame(string FrameID, ID3Info.FrameFlags Flags)
			: base(FrameID, Flags)
		{
		}

		/// <summary>
		/// Get or Set current TextOnlyFrame text
		/// </summary>
		public string Text
		{
			get { return _Text; }
			set { _Text = value; }
		}

		#region -> Override Methods and properties <-

		/// <summary>
		/// Indicate if this frame have usefull data (Text!=null,Empty)
		/// </summary>
		public override bool IsAvailable
		{
			get
			{
				if (Text == null || Text == "")
					return false;
				else
					return true;
			}
		}

		/// <summary>
		/// Get length of current frame
		/// </summary>
		public override int Length
		{
			get
			{
				// in Ascii Encoding each character is one byte
				return Text.Length;
			}
		}

		/// <summary>
		/// Get stream to save current Frame
		/// </summary>
		/// <returns>Bytes for saving this frame</returns>
		public override MemoryStream FrameStream(int MinorVersion)
		{
			MemoryStream ms = FrameHeader(MinorVersion);

			WriteText(ms, _Text, ID3Info.TextEncodings.Ascii, false);

			return ms;
		}

		#endregion
	}

	/// <summary>
	/// A Class for frames that include Text with TextEncoding
	/// </summary>
	public class TextFrame : TextOnlyFrame
	{
		/*
         * Note: This class support both URL and Text frames
         * the diffrence between these two types is: URL frame don't contain
         * TextEncoding and always use Ascii as Encoding but TextFrames contain
         * URLs start with 'W' texts with 'T'
         */
		private ID3Info.TextEncodings _TextEncoding;

		/// <summary>
		/// Create new TextFrame Class
		/// </summary>
		/// <param name="FrameID">4 Characters frame identifier</param>
		/// <param name="Flags">Flag of frame</param>
		/// <param name="Data">FileStream to read frame data from</param>
		/// <param name="Length">Maximum length of frame</param>
		internal TextFrame(string FrameID, ID3Info.FrameFlags Flags, FileStreamEx Data, int Length)
			: base(FrameID, Flags)
		{
			// If it was URL frame the TextEncoding is ascii and must not read
			if (IsUrl)
				TextEncoding = ID3Info.TextEncodings.Ascii;
			else
			{
				TextEncoding = (ID3Info.TextEncodings) Data.ReadByte();
				Length--;
				if (!IsValidEnumValue(TextEncoding, ValidatingErrorTypes.ID3Error))
					return;
			}

			Text = Data.ReadText(Length, _TextEncoding);
		}

		/// <summary>
		/// Create new TextFrame with specific information
		/// </summary>
		/// <param name="Text">Text of TextFrame</param>
		/// <param name="TextEncoding">TextEncoding of TextFrame</param>
		/// <param name="FrameID">FrameID of TextFrame</param>
		/// <param name="Flags">Flags of Frame</param>
		public TextFrame(string FrameID, ID3Info.FrameFlags Flags, string Text, ID3Info.TextEncodings TextEncoding,
		                 int Ver)
			: base(FrameID, Flags)
		{
			if (FramesInfo.IsTextFrame(FrameID, Ver) != 1)
				throw (new ArgumentException(FrameID + " is not valid TextFrame FrameID"));

			this.Text = Text;
			this.TextEncoding = TextEncoding;
		}

		protected TextFrame(string FrameID, ID3Info.FrameFlags Flags)
			: base(FrameID, Flags)
		{
		}

		/// <summary>
		/// Get or Set current frame TextEncoding
		/// </summary>
		public ID3Info.TextEncodings TextEncoding
		{
			get { return _TextEncoding; }
			set
			{
				if (IsValidEnumValue(value, ValidatingErrorTypes.Exception))
					_TextEncoding = value;
			}
		}

		/// <summary>
		/// Indicate if current frame contain URL information
		/// </summary>
		protected bool IsUrl
		{
			get
			{
				// first character of URL frames always is 'W'
				return (FrameID[0] == 'W');
			}
		}

		#region -> Override method and properties <-

		/// <summary>
		/// Get length of current frame
		/// </summary>
		public override int Length
		{
			get
			{
				// 1: Encoding
				// TextLength ( Ascii Or Unicode )
				// this frame don't contain text seprator
				return (1 + GetTextLength(Text, _TextEncoding, false));
			}
		}

		/// <summary>
		/// Indicate if this frame have usefull data (Text:null;Empty) (TextEncoding:Valid)
		/// </summary>
		public override bool IsAvailable
		{
			get
			{
				// if TextEncoding and Text value is valid this frame is valid
				// otherwise not
				if (!IsValidEnumValue(_TextEncoding, ValidatingErrorTypes.Nothing) ||
				    Text == null || Text == "")
					return false;
				else
					return true;
			}
		}

		/// <summary>
		/// Get MemoryStream of frame data
		/// </summary>
		/// <returns>MemoryStream of current frame</returns>
		public override MemoryStream FrameStream(int MinorVersion)
		{
			MemoryStream ms = FrameHeader(MinorVersion);

			if (!IsUrl)
			{
				if (ID3Info.AutoTextEncoding)
					SetEncoding();

				ms.WriteByte((byte) _TextEncoding); // Write Text Encoding
				WriteText(ms, Text, _TextEncoding, false); // Write Text
			}
			else
				WriteText(ms, Text, ID3Info.TextEncodings.Ascii, false);

			return ms;
		}

		/// <summary>
		/// Set TextEncoding according to Data of current frame
		/// </summary>
		private void SetEncoding()
		{
			if (IsAscii(Text))
				TextEncoding = ID3Info.TextEncodings.Ascii;
			else
				TextEncoding = ID3Info.DefaultUnicodeEncoding;
		}

		#endregion

		public override bool Equals(object obj)
		{
			if (obj.GetType() != GetType())
				return false;

			// if FrameID of two text frames were equal they are equal
			// ( the text is not important )
			return (FrameID == ((TextFrame) obj).FrameID);
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
	}
}